package org.dei.perla.device.channel;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;

import org.dei.perla.sys.configuration.ConfigurationManager;
import org.dei.perla.sys.device.channel.concrete.socket.SocketChannelManager;
import org.dei.perla.sys.device.channel.frame.address.concrete.SocketFrameAddress;
import org.dei.perla.utils.logger.ConsoleLogger;
import org.dei.perla.utils.logger.Logger;
import org.dei.perla.utils.logger.LogRecord.Verbosity;
import org.dei.perla.utils.messages.AdapterChannelMessage;
import org.dei.perla.utils.pipe.Pipe;


/**
 * Test di un canale SocketChannel.
 * 
 * La rete simulata è composta da due nodi sensori (B,C) e un nodo 
 * che simula una macchina alla quale i sensori si connettono.
 * I sensori 
 * i) Creano una connessione verso la macchina server
 * ii) inviano ciascuno 5 pacchetti di test verso la macchina server
 * iii) chiudono la connessione
 * 
 */
public class TestSocketChannel {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		ConsoleLogger cl = new ConsoleLogger();
		cl.setVerbosity(Verbosity.Low);
		cl.start();
		
		// Crea un thread per ogni macchina simulata
		Thread nodeA = new NodeAThread(cl);
		Thread nodeB = new NodeBThread(cl, "Nodo B","config-socket-nodeB.xml");
		Thread nodeC = new NodeBThread(cl, "Nodo C", "config-socket-nodeC.xml");
		
		// avvia i thread
		nodeA.start();
		nodeB.start();
		nodeC.start();
		
		try {
			nodeA.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		cl.stop();
		System.out.printf("Test finito!\n");
		
	}
	
	static private class NodeAThread extends Thread {
		
		Logger l;
		
		
		int n = 5; // Se si cambia settare anche in nell'altro thread
		
		NodeAThread(Logger l) {
			super("serverT");
			this.l = l;
		}
		
		public void run() {
		
			
			SocketChannelManager CM;
			ConfigurationManager conf = new ConfigurationManager("config-socket-nodeA.xml");
			conf.loggerAttach(l);
			
			conf.start();
			CM = (SocketChannelManager) conf.getChannels().get(0);
			
			CM.loggerAttach(l);
			
			Pipe<AdapterChannelMessage> channelIn = CM.getInputPipe();
			
			CM.start();
			
			for ( int i = 0; i < n*2; i++ ) {
				
				AdapterChannelMessage recv = null;
				
				// Sistema stupido per leggere da pipe, usate i Waiter in un
				// sistema reale
				while ( recv == null ) {
					// System.out.printf("Non ho ricevuto nulla\n");
					recv = channelIn.dequeue();
				}
				
				if ( recv != null )
					System.out.printf("NodoA riceve un " + recv.toString());
				else 
					System.out.printf("NodoA non ha ricevuto nulla\n");
				
			}

			try {
				sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.printf(CM.toString());
			try {
				sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			CM.stop();
			System.out.printf("Nodo A esce!\n");
		}
		
	}

	static private class NodeBThread extends Thread {
		
		Logger l;
		String config;
		String name;
		int n = 5;
		NodeBThread(Logger l,String name, String config) {
			super("clientT");
			this.l = l;
			this.config = config;
			this.name = name;
		}
		
		public void run() {
			SocketChannelManager CM;
			ConfigurationManager conf = new ConfigurationManager(config);
			conf.loggerAttach(l);
			
			try {
				sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			conf.start();
			CM = (SocketChannelManager) conf.getChannels().get(0);
			
			AdapterChannelMessage temp = null;
			
			CM.loggerAttach(l);
			
			Pipe<AdapterChannelMessage> channelOut = CM.getOutputPipe();
		
			CM.start();
			

			for ( int i = 0; i < n; i++ ) {
				int len = (int) (10*Math.random()+1);
				byte[] payload = new byte[len];
				for ( int j = 0; j < len; j++ ) {
					int b = (int) (255*Math.random());
					payload[j] = (byte) b;
				}
				try {
					temp = new AdapterChannelMessage(new SocketFrameAddress(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 4000)), payload);
				} catch (UnknownHostException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				channelOut.enqueue(temp);
				System.out.printf(name + " invia un " + temp.toString());
			}
					
			
			try {
				sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
			System.out.printf(CM.toString());
			
			try {
				sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			CM.stop();
			
			
			System.out.printf(name +" esce!\n");
		
			
		}
		
	}
	
}





